import java.util.ArrayList;
import java.util.List;

/**
 * Wrapper Classes Examples
 * This class demonstrates Java wrapper classes, autoboxing/unboxing, and their common methods
 */
public class Wrappers {
    
    public static void main(String[] args) {
        Wrappers example = new Wrappers();
        
        // Demonstrating primitive types and their wrappers
        example.demonstratePrimitiveWrappers();
        
        // Demonstrating autoboxing and unboxing
        example.demonstrateAutoboxingUnboxing();
        
        // Demonstrating common methods of wrapper classes
        example.demonstrateCommonMethods();
        
        // Practical examples using wrapper classes
        example.practicalExamples();
    }
    
    /**
     * Method to demonstrate primitive types and their wrapper classes
     */
    public void demonstratePrimitiveWrappers() {
        System.out.println("=== Primitive Types and Their Wrappers ===");
        
        // byte and Byte
        byte b = 100;
        Byte byteObj = new Byte(b);
        System.out.println("byte value: " + b + ", Byte object: " + byteObj);
        
        // short and Short
        short s = 200;
        Short shortObj = new Short(s);
        System.out.println("short value: " + s + ", Short object: " + shortObj);
        
        // int and Integer
        int i = 1000;
        Integer intObj = new Integer(i);
        System.out.println("int value: " + i + ", Integer object: " + intObj);
        
        // long and Long
        long l = 10000L;
        Long longObj = new Long(l);
        System.out.println("long value: " + l + ", Long object: " + longObj);
        
        // float and Float
        float f = 3.14f;
        Float floatObj = new Float(f);
        System.out.println("float value: " + f + ", Float object: " + floatObj);
        
        // double and Double
        double d = 2.71828;
        Double doubleObj = new Double(d);
        System.out.println("double value: " + d + ", Double object: " + doubleObj);
        
        // char and Character
        char c = 'A';
        Character charObj = new Character(c);
        System.out.println("char value: " + c + ", Character object: " + charObj);
        
        // boolean and Boolean
        boolean bool = true;
        Boolean boolObj = new Boolean(bool);
        System.out.println("boolean value: " + bool + ", Boolean object: " + boolObj);
        
        System.out.println();
    }
    
    /**
     * Method to demonstrate autoboxing and unboxing
     */
    public void demonstrateAutoboxingUnboxing() {
        System.out.println("=== Autoboxing and Unboxing ===");
        
        // Autoboxing - automatic conversion from primitive to wrapper
        System.out.println("Autoboxing examples:");
        Integer intObj = 100;  // Automatically converts int to Integer
        System.out.println("Autoboxed Integer: " + intObj);
        
        List<Double> doubleList = new ArrayList<>();
        doubleList.add(3.14);  // Automatically converts double to Double
        System.out.println("Added double to list (autoboxed): " + doubleList.get(0));
        
        // Unboxing - automatic conversion from wrapper to primitive
        System.out.println("\nUnboxing examples:");
        int intValue = intObj;  // Automatically converts Integer to int
        System.out.println("Unboxed int value: " + intValue);
        
        double doubleValue = doubleList.get(0);  // Automatically converts Double to double
        System.out.println("Unboxed double value: " + doubleValue);
        
        // Arithmetic operations with wrappers (unboxing happens automatically)
        Integer x = 10;
        Integer y = 20;
        int sum = x + y;  // Unboxing happens here
        System.out.println("Sum of wrapped integers: " + sum);
        
        System.out.println();
    }
    
    /**
     * Method to demonstrate common methods of wrapper classes
     */
    public void demonstrateCommonMethods() {
        System.out.println("=== Common Methods of Wrapper Classes ===");
        
        // Integer class methods
        System.out.println("Integer class methods:");
        String intStr = "123";
        int parsedInt = Integer.parseInt(intStr);
        System.out.println("Parsed integer from string '" + intStr + "': " + parsedInt);
        
        String binaryStr = Integer.toBinaryString(10);
        System.out.println("Binary representation of 10: " + binaryStr);
        
        String hexStr = Integer.toHexString(255);
        System.out.println("Hexadecimal representation of 255: " + hexStr);
        
        int maxInt = Integer.max(10, 20);
        System.out.println("Maximum of 10 and 20: " + maxInt);
        
        // Double class methods
        System.out.println("\nDouble class methods:");
        String doubleStr = "3.14159";
        double parsedDouble = Double.parseDouble(doubleStr);
        System.out.println("Parsed double from string '" + doubleStr + "': " + parsedDouble);
        
        boolean isNaN = Double.isNaN(Double.NaN);
        System.out.println("Is NaN check: " + isNaN);
        
        // Character class methods
        System.out.println("\nCharacter class methods:");
        char ch = 'A';
        boolean isDigit = Character.isDigit(ch);
        System.out.println("Is '" + ch + "' a digit? " + isDigit);
        
        boolean isLetter = Character.isLetter(ch);
        System.out.println("Is '" + ch + "' a letter? " + isLetter);
        
        char lowerCh = Character.toLowerCase(ch);
        System.out.println("Lowercase of '" + ch + "': " + lowerCh);
        
        // Boolean class methods
        System.out.println("\nBoolean class methods:");
        String boolStr = "true";
        boolean parsedBool = Boolean.parseBoolean(boolStr);
        System.out.println("Parsed boolean from string '" + boolStr + "': " + parsedBool);
        
        String boolStr2 = "false";
        boolean parsedBool2 = Boolean.parseBoolean(boolStr2);
        System.out.println("Parsed boolean from string '" + boolStr2 + "': " + parsedBool2);
        
        System.out.println();
    }
    
    /**
     * Practical examples using wrapper classes
     */
    public void practicalExamples() {
        System.out.println("=== Practical Examples ===");
        
        // Example 1: Working with collections (which require objects)
        System.out.println("Example 1: Working with collections");
        List<Integer> numbers = new ArrayList<>();
        // Adding primitive ints to List (autoboxing)
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        
        // Retrieving values (auto-unboxing when needed)
        int sum = 0;
        for (Integer number : numbers) {
            sum += number;  // auto-unboxing
        }
        System.out.println("Sum of numbers: " + sum);
        
        // Example 2: Handling null values
        System.out.println("\nExample 2: Handling null values");
        Integer nullableInt = null;
        // This would cause NullPointerException if we tried to unbox it directly
        if (nullableInt != null) {
            int primitiveInt = nullableInt;  // safe unboxing
            System.out.println("Safe unboxed value: " + primitiveInt);
        } else {
            System.out.println("Integer object is null, cannot unbox");
        }
        
        // Example 3: Converting between bases
        System.out.println("\nExample 3: Converting between bases");
        int decimal = 42;
        System.out.println("Decimal " + decimal + " in binary: " + Integer.toBinaryString(decimal));
        System.out.println("Decimal " + decimal + " in octal: " + Integer.toOctalString(decimal));
        System.out.println("Decimal " + decimal + " in hexadecimal: " + Integer.toHexString(decimal));
        
        // Example 4: Parsing strings with error handling
        System.out.println("\nExample 4: Parsing strings with error handling");
        String[] testStrings = {"123", "abc", "45.67", "999"};
        for (String str : testStrings) {
            try {
                int parsed = Integer.parseInt(str);
                System.out.println("Successfully parsed '" + str + "' to " + parsed);
            } catch (NumberFormatException e) {
                System.out.println("Failed to parse '" + str + "' to integer");
            }
        }
        
        System.out.println();
    }
}